package com.matt.service.impl;

import com.matt.domain.Notice.Notice;
import com.matt.domain.Notice.NoticeClasses;
import com.matt.domain.rel.RelClassesTeacher;
import com.matt.foundation.DO.NoticeDO;
import com.matt.commons.dto.sso.StaffDTO;
import com.matt.commons.exception.BusinessException;

import com.matt.foundation.model.ErrorCode;
import com.matt.foundation.model.MemVerificationCache;
import com.matt.repository.ClassesRepository;
import com.matt.repository.base.NoticeClassesRelRepository;
import com.matt.repository.notice.NoticeClassesRepository;
import com.matt.repository.notice.NoticeRepository;
import com.matt.repository.rel.RelClassesTeacherRepository;
import com.matt.service.NoticeService;
import com.matt.service.remoteCall.SsoCallService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.assertj.core.util.Lists;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;

import javax.persistence.criteria.*;
import javax.transaction.Transactional;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;


@Service
@Slf4j
public class NoticeServiceImpl implements NoticeService {

    @Autowired
    private NoticeRepository noticeRepository;

    @Autowired
    private SsoCallService ssoCallService;

    @Value("${spring.redis.host}")
    private String host;

    @Autowired
    private MemVerificationCache cache;

    @Autowired
    private ClassesRepository classesRepository ;

    @Autowired
    private NoticeClassesRepository noticeClassesRepository;

    @Autowired
    private RelClassesTeacherRepository relClassesTeacherRepository ;

    @Autowired
    private NoticeClassesRelRepository noticeClassesRelRepository;

    @Transactional
   // @OptsTrace(value = "0451") //在TeachOperationLogAop中记录日志
    @Override
    public Notice addNotice(String title, String content, Integer noticeType, String staffId, String areaId) {
        StaffDTO staff = ssoCallService.getStaffDTO(null, staffId);
        String headImgUrl =  staff.getHeadImgUrl();
        Notice notice = Notice.of(title, content, staffId, staff.getRealName(), headImgUrl, areaId, noticeType);
        noticeRepository.save(notice);
        return notice;
    }

    @Override
    public Page<Notice> getNoticeListByAreaId(String areaId,Integer noticeType, Integer pageNum, Integer pageSize) {
        Specification<Notice> specification = new Specification<Notice>() {
            @Override
            public Predicate toPredicate(Root<Notice> root, CriteriaQuery<?> query, CriteriaBuilder criteriaBuilder) {
                List<Predicate> predicates = new ArrayList<>();

                if (StringUtils.isNotBlank(areaId))
                    predicates.add(criteriaBuilder.and(criteriaBuilder.equal(root.get("areaId"), areaId)));
                if (null != noticeType)
                    predicates.add(criteriaBuilder.and(criteriaBuilder.equal(root.get("noticeType"),noticeType )));
                predicates.add(criteriaBuilder.and(criteriaBuilder.equal(root.get("deleted"),false )));
                query.where(predicates.toArray(new Predicate[predicates.size()]));
                query.orderBy(criteriaBuilder.desc(root.get("created")));
                return query.getRestriction();
            }
        };
        Page<Notice> noticePage = noticeRepository.findAll(specification, PageRequest.of(pageNum, pageSize));
        List<Notice> list = Lists.newArrayList();
        noticePage.getContent().stream().forEach(o -> {
            list.add(o);
        });

        return new PageImpl(list, PageRequest.of(pageNum, pageSize), noticePage.getTotalElements());
    }


    @Transactional
    @Override
    public Notice deleteNotice(String ticket, String noticeId) {
        String staffId = cache.getStaffId(ticket);
        StaffDTO staff = ssoCallService.getStaffDTO(null, staffId);
        if (Objects.isNull(staff))
            throw new BusinessException(ErrorCode.STAFF_NOT_EXIST, "用户不存在");

        Notice notice = noticeRepository.getOne(noticeId);
        if (Objects.isNull(notice))
            throw new BusinessException(ErrorCode.ID_IS_ERROR, "ID错误");

   /*     String operatorId = notice.getOperatorId();
        if (!operatorId.equals(staffId))
            throw new BusinessException(ErrorCode.PROMISSION_DELINED, "权限不足");
*/

        notice.setDeleted(true);
        noticeRepository.save(notice);

        List<NoticeClasses> list = noticeClassesRepository.findByNoticeId(noticeId);
        for(NoticeClasses noticeClasses : list){
            noticeClasses.setDeleted(true);
            noticeClassesRepository.save(noticeClasses);
        }

        return notice ;
    }

    @Transactional
    @Override
    public Notice addNoticeByClasses(String title, String content, Integer noticeType, String staffId, String areaId, String[] classesIdArray) {
        StaffDTO staff = ssoCallService.getStaffDTO(null, staffId);
        String headImgUrl =  staff.getHeadImgUrl();
        Notice notice = Notice.of(title, content, staffId, staff.getRealName(), headImgUrl, areaId, noticeType);
        noticeRepository.save(notice);

        String noticeId = notice.getId();
        for(String classesId : classesIdArray){
            NoticeClasses noticeClasses = new NoticeClasses();
            noticeClasses.setClassesId(classesId);
            noticeClasses.setNoticeId(noticeId);
            noticeClasses.setAreaId(areaId);
            if(classesId.equals("1")){
                noticeClasses.setClassesName("全体老师");
            }else {
                String classesName = classesRepository.getOne(classesId).getName();
                noticeClasses.setClassesName(classesName);
            }

            noticeClassesRepository.save(noticeClasses);
        }
        return notice;
    }

    @Override
    public Notice noticeDetail(String noticeId) {
        Notice notice =  noticeRepository.getOne(noticeId);
        List<NoticeClasses> noticeClassesList = noticeClassesRepository.findByNoticeId(noticeId);
        List<NoticeDO> noticeDOs =  new ArrayList<>();
        for(NoticeClasses noticeClasses : noticeClassesList){
            NoticeDO noticeDO = new NoticeDO();
            noticeDO.setClassesName(noticeClasses.getClassesName());
            noticeDO.setClassesId(noticeClasses.getClassesId());
            noticeDOs.add(noticeDO);
        }

        notice.setNoticeClassList(noticeDOs);
        return notice ;
    }


    @Override
    public Page<Notice> getNoticeListByStaffId(String staffId,String areaId,Integer noticeType, Integer pageNum, Integer pageSize) {
        List<String> classIdList = new ArrayList<>();
        List<String> noticeIdList = new ArrayList<>();
        List<RelClassesTeacher> relClassesTeacherList = relClassesTeacherRepository.findByStaffId(staffId);
        for(RelClassesTeacher relClassesTeacher : relClassesTeacherList){
            classIdList.add(relClassesTeacher.getClassesId());
        }

        classIdList.add("1");//全部老师班级ID 补充
        String [] strings = new String[classIdList.size()];
        classIdList.toArray(strings);

        List<NoticeClasses> noticeClassesList =  noticeClassesRepository.findByAreaIdAndClassesIdInAndDeleted(areaId, strings, false);
        for(NoticeClasses noticeClasses : noticeClassesList){
            noticeIdList.add(noticeClasses.getNoticeId());
        }


        Specification<Notice> specification = new Specification<Notice>() {
            @Override
            public Predicate toPredicate(Root<Notice> root, CriteriaQuery<?> query, CriteriaBuilder criteriaBuilder) {
                List<Predicate> predicates = new ArrayList<>();
                predicates.add(criteriaBuilder.and(criteriaBuilder.equal(root.get("deleted"), false)));
                Expression<String> exp = root.<String>get("id");
                predicates.add(exp.in(noticeIdList));
                query.where(predicates.toArray(new Predicate[predicates.size()]));
                query.orderBy(criteriaBuilder.desc(root.get("created")));
                return query.getRestriction();
            }
        };
        Page<Notice> noticePage = noticeRepository.findAll(specification, PageRequest.of(pageNum, pageSize));
        List<Notice> list = Lists.newArrayList();
        noticePage.getContent().stream().forEach(o -> {
            list.add(o);
        });

        return new PageImpl(list, PageRequest.of(pageNum, pageSize), noticePage.getTotalElements());
    }


}
